﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

namespace AIStudio.Wpf.DiagramDesigner
{
    public class DiagramOption
    {
        public LayoutOption LayoutOption
        {
            get; set;
        } = new LayoutOption();

        public ShortcutOption ShortcutOption
        {
            get; set;
        } = new ShortcutOption();

        public SnappingOption SnappingOption
        {
            get; set;
        } = new SnappingOption();
    }

    public class LayoutOption : BindableBase
    {
        private PageSizeType _pageSizeType = PageSizeType.A4;
        public PageSizeType PageSizeType
        {
            get
            {
                return _pageSizeType;
            }
            set
            {
                SetProperty(ref _pageSizeType, value);
                RaisePropertyChanged(nameof(PageSize));
            }
        }

        private Size _pageSize = new Size(1000, 600);
        public Size PageSize
        {
            get
            {
                if (PageSizeOrientation == PageSizeOrientation.Vertical)
                {
                    return GetPageSize();
                }
                else
                {
                    return new Size(GetPageSize().Height, GetPageSize().Width);
                }
            }
            set
            {
                if (SetProperty(ref _pageSize, value))
                {
                    RaisePropertyChanged(nameof(PhysicalPageSize));
                }
            }
        }

        public Size PhysicalPageSize
        {
            get
            {
                return new Size(ScreenHelper.WidthToMm(PageSize.Width), ScreenHelper.WidthToMm(PageSize.Height));
            }
            set
            {
                PageSize = new Size(ScreenHelper.MmToWidth(value.Width), ScreenHelper.MmToWidth(value.Height));
            }
        }

        public Size GetPageSize()
        {
            Size size = _pageSize;
            switch (PageSizeType)
            {
                case PageSizeType.A3: size = new Size(297, 420); break;
                case PageSizeType.A4: size = new Size(210, 297); break;
                case PageSizeType.A5: size = new Size(148, 210); break;
                case PageSizeType.B4: size = new Size(257, 364); break;
                case PageSizeType.B5: size = new Size(176, 250); break;
                case PageSizeType.DLEnvelope: size = new Size(110, 220); break;
                case PageSizeType.C5Envelope: size = new Size(162, 229); break;
                case PageSizeType.Quarto: size = new Size(215, 275); break;
                case PageSizeType.C6Quarto: size = new Size(114, 162); break;
                case PageSizeType.B5Quarto: size = new Size(176, 250); break;
                case PageSizeType.ItalyQuarto: size = new Size(110, 230); break;
                case PageSizeType.A4small: size = new Size(210, 297); break;
                case PageSizeType.GermanStdFanfold: size = new Size(215.9, 304.8); break;
                case PageSizeType.GermanLegalFanfold: size = new Size(203.2, 330.2); break;
                case PageSizeType.PRC16K: size = new Size(146, 215); break;
                case PageSizeType.PRC32K: size = new Size(97, 151); break;
                case PageSizeType.Letter: size = new Size(215.9, 279.4); break;
                case PageSizeType.Folio: size = new Size(215.9, 330.2); break;
                case PageSizeType.Legal: size = new Size(215.9, 355.6); break;
                case PageSizeType.Executive: size = new Size(184.15, 266.7); break;
                case PageSizeType.Statement: size = new Size(139.7, 215.9); break;
                case PageSizeType.Envelope: size = new Size(104.77, 241.3); break;
                case PageSizeType.MonarchEnvelope: size = new Size(98.425, 190.5); break;
                case PageSizeType.Tabloid: size = new Size(279.4, 431.8); break;
                case PageSizeType.LetterSmall: size = new Size(215.9, 279.4); break;
                case PageSizeType.CSheet: size = new Size(431.8, 558.8); break;
                case PageSizeType.DSheet: size = new Size(558.8, 863.6); break;
                case PageSizeType.ESheet: size = new Size(863.6, 1117.6); break;
            }

            return new Size(ScreenHelper.MmToWidth(size.Width), ScreenHelper.MmToWidth(size.Height));
        }

        private PageSizeOrientation _pageSizeOrientation;
        public PageSizeOrientation PageSizeOrientation
        {
            get
            {
                return _pageSizeOrientation;
            }
            set
            {
                SetProperty(ref _pageSizeOrientation, value);
                RaisePropertyChanged(nameof(PageSize));
            }
        }

        private PageUnit _pageUnit = PageUnit.cm;
        [Browsable(false)]
        public PageUnit PageUnit
        {
            get
            {
                return _pageUnit;
            }
            set
            {
                if (value != PageUnit.cm && value != PageUnit.inch)
                {
                    return;
                }
                SetProperty(ref _pageUnit, value);
            }
        }

        private Size _gridCellSize = new Size(100, 100);
        public Size GridCellSize
        {
            get
            {
                return _gridCellSize;
            }
            set
            {
                SetProperty(ref _gridCellSize, value);
            }
        }

        public double GridCellWidth
        {
            get
            {
                return _gridCellSize.Width;
            }
            set
            {
                _gridCellSize.Width = value;
                RaisePropertyChanged(nameof(PhysicalGridCellWidth));
                RaisePropertyChanged(nameof(GridCellSize));
            }
        }

        public double GridCellHeight
        {
            get
            {
                return _gridCellSize.Height;
            }
            set
            {
                _gridCellSize.Height = value;
                RaisePropertyChanged(nameof(PhysicalGridCellHeight));
                RaisePropertyChanged(nameof(GridCellSize));
            }
        }

        public Size PhysicalGridCellSize
        {
            get
            {
                return new Size(ScreenHelper.WidthToMm(GridCellSize.Width), ScreenHelper.WidthToMm(GridCellSize.Height));
            }
            set
            {
                GridCellSize = new Size(ScreenHelper.MmToWidth(value.Width), ScreenHelper.MmToWidth(value.Height));
            }
        }

        public double PhysicalGridCellWidth
        {
            get
            {
                return ScreenHelper.WidthToMm(GridCellWidth);
            }
            set
            {
                GridCellWidth = ScreenHelper.MmToWidth(value);
            }
        }

        public double PhysicalGridCellHeight
        {
            get
            {
                return ScreenHelper.WidthToMm(GridCellHeight);
            }
            set
            {
                GridCellHeight = ScreenHelper.MmToWidth(value);
            }
        }

        private Color _pageBackground = Colors.White;
        public Color PageBackground
        {
            get
            {
                return _pageBackground;
            }
            set
            {
                SetProperty(ref _pageBackground, value);
            }
        }

        private bool _showGrid = true;
        public bool ShowGrid
        {
            get
            {
                return _showGrid;
            }
            set
            {
                SetProperty(ref _showGrid, value);
            }
        }

        private Color _gridColor = Colors.LightGray;
        public Color GridColor
        {
            get
            {
                return _gridColor;
            }
            set
            {
                SetProperty(ref _gridColor, value);
            }
        }

        private Size _gridMarginSize = new Size(28, 28);
        public Size GridMarginSize
        {
            get
            {
                return _gridMarginSize;
            }
            set
            {
                SetProperty(ref _gridMarginSize, value);
            }
        }

        public double GridMarginWidth
        {
            get
            {
                return _gridMarginSize.Width;
            }
            set
            {
                _gridMarginSize.Width = value;
                RaisePropertyChanged(nameof(GridMarginSize));
            }
        }

        public double GridMarginHeight
        {
            get
            {
                return _gridMarginSize.Height;
            }
            set
            {
                _gridMarginSize.Height = value;
                RaisePropertyChanged(nameof(GridMarginSize));
            }
        }

        public Size PhysicalGridMarginSize
        {
            get
            {
                return new Size(ScreenHelper.WidthToMm(GridMarginSize.Width), ScreenHelper.WidthToMm(GridMarginSize.Height));
            }
            set
            {
                GridMarginSize = new Size(ScreenHelper.MmToWidth(value.Width), ScreenHelper.MmToWidth(value.Height));
            }
        }

        public double PhysicalGridMarginWidth
        {
            get
            {
                return ScreenHelper.WidthToMm(GridMarginWidth);
            }
            set
            {
                GridMarginWidth = ScreenHelper.MmToWidth(value);
            }
        }

        public double PhysicalGridMarginHeight
        {
            get
            {
                return ScreenHelper.WidthToMm(GridMarginHeight);
            }
            set
            {
                GridMarginHeight = ScreenHelper.MmToWidth(value);
            }
        }

        private CellHorizontalAlignment _cellHorizontalAlignment;
        [Browsable(false)]
        public CellHorizontalAlignment CellHorizontalAlignment
        {
            get
            {
                return _cellHorizontalAlignment;
            }
            set
            {
                SetProperty(ref _cellHorizontalAlignment, value);
            }
        }

        private CellVerticalAlignment _cellVerticalAlignment;
        [Browsable(false)]
        public CellVerticalAlignment CellVerticalAlignment
        {
            get
            {
                return _cellVerticalAlignment;
            }
            set
            {
                SetProperty(ref _cellVerticalAlignment, value);
            }
        }

        public bool AllowDrop
        {
            get; set;
        } = true;
    }

    public class SnappingOption
    {
        public bool EnableSnapping
        {
            get; set;
        }
        public double SnappingRadius
        {
            get; set;
        } = 50;
        public double BlockSnappingRadius
        {
            get; set;
        } = 30;
    }

    public class ShortcutOption
    {
        [Description("Select All shortcut (CTRL+A by default)")]
        public Func<KeyEventArgs, bool> SelectAll
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.A;

        [Description("Copy shortcut (CTRL+C by default)")]
        public Func<KeyEventArgs, bool> Copy
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.C;

        [Description("Paste shortcut (CTRL+V by default)")]
        public Func<KeyEventArgs, bool> Paste
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.V;

        [Description("Cut shortcut (CTRL+X by default)")]
        public Func<KeyEventArgs, bool> Cut
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.X;

        [Description("Undo shortcut (CTRL+Z by default)")]
        public Func<KeyEventArgs, bool> Undo
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.Z;

        [Description("Undo shortcut (CTRL+Y by default)")]
        public Func<KeyEventArgs, bool> Redo
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.Y;

        [Description("Delete shortcut (Delete by default)")]
        public Func<KeyEventArgs, bool> Delete
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.None && e.Key == Key.Delete;

        [Description("Left Move shortcut (Left by default)")]
        public Func<KeyEventArgs, bool> LeftMove
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.None && e.Key == Key.Left;

        [Description("Right Move shortcut (Right by default)")]
        public Func<KeyEventArgs, bool> RightMove
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.None && e.Key == Key.Right;

        [Description("Up Move shortcut (Up by default)")]
        public Func<KeyEventArgs, bool> UpMove
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.None && e.Key == Key.Up;

        [Description("Down Move shortcut (Down by default)")]
        public Func<KeyEventArgs, bool> DownMove
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.None && e.Key == Key.Down;

        [Description("Group Keyboard shortcut (CTRL+G by default)")]
        public Func<KeyEventArgs, bool> Group
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.G;

        [Description("Ungroup Keyboard shortcut (Shift+G by default)")]
        public Func<KeyEventArgs, bool> Ungroup
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.Shift | e.Key == Key.G;

        [Description("Search shortcut (CTRL+F by default)")]
        public Func<KeyEventArgs, bool> Search
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.Control | e.Key == Key.F;

        [Description("Search Down shortcut (F3 by default)")]
        public Func<KeyEventArgs, bool> SearchDown
        {
            get; set;
        } = e =>  e.Key == Key.F3;

        [Description("Search Up shortcut (Shift+F3 by default)")]
        public Func<KeyEventArgs, bool> SearchUp
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.Shift | e.Key == Key.F3;

        [Description("Replace shortcut (Alt+R by default)")]
        public Func<KeyEventArgs, bool> Replace
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.Alt | e.Key == Key.R;

        [Description("Replace All shortcut (Alt+A by default)")]
        public Func<KeyEventArgs, bool> ReplaceAll
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.Alt | e.Key == Key.A;

        [Description("Next Node (CEnter by default)")]
        public Func<KeyEventArgs, bool> Next
        {
            get; set;
        } = e => e.KeyboardDevice.Modifiers == ModifierKeys.None && e.Key == Key.Enter;
    }
}
